﻿// Copyright (c) 2013, Simon Carter.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted 
// provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this list of 
//   conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice, this list of 
//  conditions and the following disclaimer in the documentation and/or other materials provided 
//  with the distribution.

// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// History
// Initial Release - Simon Carter
//

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ErrorManager.Console.Controls
{
    /// <summary>
    /// Control to manage system users
    /// </summary>
    public partial class UserManagement : BaseControlClass
    {
        private const string NEW_USER_NAME = "New User";
        private const string VALID_CHARS = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@_.";
        private const int MIN_PASSWORD_LENGTH = 6;

        private bool _newUser = false;

        #region Constructors

        /// <summary>
        /// Constructor
        /// </summary>
        public UserManagement()
        {
            InitializeComponent();
        }

        #endregion Constructors

        #region Overridden Methods

        internal override void ProcessMessage(TCPMessageServer.Message message)
        {
            if (this.InvokeRequired)
            {
                ErrorManager.Console.ErrorServerConsoleForm.ProcessMessageEventHandler eh = new ErrorManager.Console.ErrorServerConsoleForm.ProcessMessageEventHandler(ProcessMessage);
                this.Invoke(eh, new object[] { message });
            }
            else
            {
                switch (message.Title)
                {
                    case "GET_USERS":
                        lstUsers.Items.Clear();
                        string[] users = message.Contents.Split('\r');

                        foreach (string s in users)
                            if (!String.IsNullOrEmpty(s.Trim()))
                                lstUsers.Items.Add(s.Trim());

                        break;

                    case "GET_USER_PASSWORD":
                        txtPassword.Text = message.Contents;
                        
                        break;

                    case "GET_USER_ACTIVE":
                        cbUserActive.Checked = Convert.ToBoolean(message.Contents);
                        
                        break;

                    case "GET_USER_PERMISSIONS":
                        cbManageSystemUsers.Checked = message.Contents.Contains("ManageSystemUsers");
                        cbConfigureServer.Checked = message.Contents.Contains("ConfigureServer");
                        
                        break;

                    case "GET_USER_LAST_LOGIN":
                        this.Cursor = Cursors.Arrow;
                        lblLastLoggedIn.Text = message.Contents;
                        
                        break;

                    case "DELETE_USER":
                        if (Convert.ToBoolean(message.Contents))
                            Client.SendMessage(TCPMessageServer.Message.Command("GET_USERS"));

                        break;

                    case "GET_USER_SPACE":
                        lblDiskSpaceUsed.Text = message.Contents;

                        break;
                }

                UpdateUI();
            }
        }

        internal override void Initialise(TCPMessageServer.MessageClient client)
        {
            base.Initialise(client);
            client.SendMessage(TCPMessageServer.Message.Command("GET_USERS"));
        }

        #endregion Overridden Methods

        #region Overridden Properties

        /// <summary>
        /// Name of tab within the console
        /// </summary>
        internal override string TabName
        {
            get
            {
                return ("Users");
            }
        }

        /// <summary>
        /// Return permission associated with the control
        /// </summary>
        internal override string Permission
        {
            get
            {
                return ("ManageSystemUsers");
            }
        }

        #endregion Pverridden Properties

        private void UpdateUI()
        {
            bool UserSelected = lstUsers.SelectedIndex > -1 || _newUser;

            btnSave.Enabled = UserSelected;
            btnDelete.Enabled = UserSelected;
            btnCreateNew.Enabled = !_newUser;
            txtUserName.Enabled = UserSelected;
            txtPassword.Enabled = UserSelected;
            cbUserActive.Enabled = UserSelected;
            gbPermissions.Enabled = UserSelected;
            lblLastLoggedIn.Enabled = UserSelected;
            lblLastLogin.Enabled = UserSelected;
            lblPassword.Enabled = UserSelected;
            lblUserName.Enabled = UserSelected;
            lblDiskSpace.Enabled = UserSelected;
            lblDiskSpaceUsed.Enabled = UserSelected;

            txtUserName.ReadOnly = !_newUser;
        }

        private void lstUsers_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lstUsers.SelectedIndex == -1)
                return;

            string user = lstUsers.SelectedItem.ToString();
            txtUserName.Text = user;

            if (_newUser)
            {
                if (user != NEW_USER_NAME)
                {
                    lstUsers.Items.Remove(NEW_USER_NAME);
                    txtUserName.ReadOnly = true;
                    _newUser = false;
                }
                else
                {
                    return;
                }
            }

            this.Cursor = Cursors.WaitCursor;
            Client.SendMessage(TCPMessageServer.Message.Command("GET_USER_SPACE", user));
            Client.SendMessage(TCPMessageServer.Message.Command("GET_USER_PASSWORD", user));
            Client.SendMessage(TCPMessageServer.Message.Command("GET_USER_ACTIVE", user));
            Client.SendMessage(TCPMessageServer.Message.Command("GET_USER_PERMISSIONS", user));
            Client.SendMessage(TCPMessageServer.Message.Command("GET_USER_LAST_LOGIN", user));
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            try
            {
                if (txtPassword.Text.Length < MIN_PASSWORD_LENGTH)
                    throw new Exception("Password too short!");

                if (_newUser)
                {
                    if (UserNameExists(txtUserName.Text))
                        throw new Exception("Username already exists");

                    Client.SendMessage(TCPMessageServer.Message.Command("USER_CREATE", txtUserName.Text));
                }
                else
                {
                    if (lstUsers.SelectedIndex == -1)
                        return;
                }

                string user = txtUserName.Text;
                int permissions = cbConfigureServer.Checked ? Convert.ToInt32(cbConfigureServer.Tag) : 0;
                permissions += cbManageSystemUsers.Checked ? Convert.ToInt32(cbManageSystemUsers.Tag) : 0;

                Client.SendMessage(TCPMessageServer.Message.Command("SET_USER_PASSWORD", String.Format("{0}${1}", user, txtPassword.Text)));
                Client.SendMessage(TCPMessageServer.Message.Command("SET_USER_ACTIVE", String.Format("{0}${1}", user, cbUserActive.Checked.ToString())));
                Client.SendMessage(TCPMessageServer.Message.Command("SET_USER_PERMISSIONS", String.Format("{0}${1}", user, permissions.ToString())));

                if (_newUser)
                {
                    _newUser = false;
                    Client.SendMessage(TCPMessageServer.Message.Command("GET_USERS"));
                }
            }
            catch (Exception err)
            {
                MessageBox.Show(err.Message, "Error");
            }
        }

        private void btnDelete_Click(object sender, EventArgs e)
        {
            if (_newUser)
            {
                txtUserName.ReadOnly = true;
                _newUser = false;
                lstUsers.SelectedIndex = 0;
            }
            else
            {
                string user = lstUsers.SelectedItem.ToString();

                if (MessageBox.Show("Are you sure you want to delete this user?", "Delete User", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
                {
                    Client.SendMessage(TCPMessageServer.Message.Command("DELETE_USER", user));
                    Client.SendMessage(TCPMessageServer.Message.Command("GET_USERS"));
                }
            }
        }

        private void btnCreateNew_Click(object sender, EventArgs e)
        {
            _newUser = true;
            lstUsers.SelectedIndex = -1;
            int i = 0;
            string newUser;
            
            do
            {
                i++;
                newUser = String.Format("{0} {1}", NEW_USER_NAME, i);
            } while (UserNameExists(newUser));

            txtPassword.Text = String.Empty;
            txtUserName.Text = newUser;
            cbConfigureServer.Checked = false;
            cbManageSystemUsers.Checked = false;
            cbUserActive.Checked = false;
            UpdateUI();
        }

        private bool UserNameExists(string userName)
        {
            foreach (string s in lstUsers.Items)
            {
                if (s.ToLower() == userName.ToLower())
                    return (true);
            }

            return (false);
        }

        private void txtPassword_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (!VALID_CHARS.Contains(e.KeyChar))
                e.Handled = true;
        }
    }
}
